/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/mount.h>

#include "update_misc_charge.h"
#include "fs_manager/fs_manager.h"
#include "securec.h"
#include "init_utils.h"
#include "beget_ext.h"

#define MAX_COMMAND_SIZE 32
#define MAX_UPDATE_SIZE 1280
#define MAX_RESERVED_SIZE 736

struct MiscUpdateMessage {
    char command[MAX_COMMAND_SIZE];
    char update[MAX_UPDATE_SIZE];
    char reserved[MAX_RESERVED_SIZE];
};

static int MiscWriteUpdaterMessage(const char *path, const struct MiscUpdateMessage *msg)
{
    int ret = -1;
    FILE *fp = NULL;

    if (path == NULL) {
        return ret;
    }

    char *realPath = realpath(path, NULL);
    if (realPath != NULL) {
        fp = fopen(realPath, "rb+");
        free(realPath);
        realPath = NULL;
    }

    if (fp != NULL) {
        size_t writeLen = fwrite(msg, sizeof(struct MiscUpdateMessage), 1, fp);
        (void)fclose(fp);
        BEGET_ERROR_CHECK(writeLen == 1, return -1, "Failed to write misc for reboot");
        ret = 0;  
    }
    return ret;
}

static int MiscReadUpdaterMessage(const char *path, struct MiscUpdateMessage *msg)
{
    int ret = -1;
    FILE *fp = NULL;

    if (path == NULL) {
        return ret;
    }

    char *realPath = realpath(path, NULL);
    if (realPath != NULL) {
        fp = fopen(realPath, "rb");
        free(realPath);
        realPath = NULL;
    }

    if (fp != NULL) {
        size_t readLen = fread(msg, 1, sizeof(struct MiscUpdateMessage), fp);
        (void)fclose(fp);
        BEGET_ERROR_CHECK(readLen > 0, return -1, "Failed to read misc for reboot");
        ret = 0;
    }
    return ret;
}

void WritePoweroffChargeFlag()
{
    BEGET_LOGI("Enter WritePoweroffChargeFlag()");
    char miscFile[PATH_MAX] = {0};
    int ret = GetBlockDevicePath(DEVICE_MISC_BLOCK, miscFile, PATH_MAX);
    BEGET_ERROR_CHECK(ret == 0, return, "Failed to get misc path");
    struct MiscUpdateMessage msg;
    ret = MiscReadUpdaterMessage(miscFile, &msg);
    BEGET_ERROR_CHECK(ret == 0, return, "Failed to get misc info for %s.", msg.command);

    ret = snprintf_s(msg.command, MAX_COMMAND_SIZE, MAX_COMMAND_SIZE - 1, "%s", DEVICE_BOOT_STATUS);
    BEGET_ERROR_CHECK(ret > 0, return, "Failed to format cmd for %s.", msg.command);

    ret = snprintf_s(msg.update, MAX_UPDATE_SIZE, MAX_UPDATE_SIZE - 1, "%s", DEVICE_CMD_CHARGE);
    BEGET_ERROR_CHECK(ret > 0, return, "Failed to format cmd for %s.", msg.update);

    msg.command[MAX_COMMAND_SIZE - 1] = 0;

    if (MiscWriteUpdaterMessage(miscFile, &msg) == 0) {
        BEGET_LOGI("Write PowerOffCharge flag to Misc successfully.");
    } else {
        BEGET_LOGE("Failed to write PowerOffCharge flag to Misc.");
    }

    BEGET_LOGI("Exit WritePoweroffChargeFlag()");
    return;
}

void ClearPowerOffChargeFlag()
{
    BEGET_LOGI("Clear Poweroff charge flag");
    char miscFile[PATH_MAX] = {0};
    int ret = GetBlockDevicePath(DEVICE_MISC_BLOCK, miscFile, PATH_MAX);
    BEGET_ERROR_CHECK(ret == 0, return, "Failed to get misc path");
    struct MiscUpdateMessage msg;

    ret = snprintf_s(msg.command, MAX_COMMAND_SIZE, MAX_COMMAND_SIZE - 1, "%s", NULL);
    BEGET_ERROR_CHECK(ret > 0, return, "Failed to format cmd for %s.", msg.command);
    msg.command[MAX_COMMAND_SIZE - 1] = 0;

    if (MiscWriteUpdaterMessage(miscFile, &msg) == 0) {
        BEGET_LOGE("Clear misc successfully.");
    }

    return;
}